home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / XLIBP202.ZIP / XGIF2.PAS < prev    next >
Pascal/Delphi Source File  |  1994-06-20  |  19KB  |  769 lines

  1. unit XGif2;
  2. { ************************************************
  3.   **    GIF Decoding and Encoding procedures    **
  4.   **        for Borland/Turbo Pascal 7.0        **
  5.   **                                            **
  6.   **     Written by Tristan Tarrant, 1994       **
  7.   **                                            **
  8.   **        ( Supports GIF87a/GIF89a )          **
  9.     ************************************************ }
  10.  
  11. interface
  12.  
  13. uses
  14.     Dos,XMisc2;
  15.  
  16. const
  17.     { Error constants used in GIF decoder }
  18.     GoodRead      = 0; { No errors encountered during encoding/decoding }
  19.     BadFile       = 1; { Physical problem with the media}
  20.     BadRead       = 2; { Could not read/interpret part of the file }
  21.     UnexpectedEOF = 3; { File too short during decoding}
  22.     BadCode       = 4; { Code encountered during decoding was not expected}
  23.     BadFirstCode  = 5; { The first code was invalid}
  24.     NoFile        = 6; { Could not open the file for read/write}
  25.     BadSymbolSize = 7; { Number of bits not supported}
  26.     NoCode        = -1;
  27.  
  28. Type
  29.     GifLineProcType = procedure( Var pixels; line, width : integer );
  30.     GifPixelProcType = function : integer;
  31.  
  32. Var
  33.     { Pointers to custom procedures to deal with lines. GifOutLineProc
  34.         is called with three parameters : an untyped var, containing
  35.         the uncompressed data, and two integer values, containing the
  36.         line number and the width of the line.
  37.         GifInPixelProc should instead return a pixels value, -1 if at the
  38.         end of the data. }
  39.  
  40.     GifOutLineProc : GifLineProcType;
  41. { GifOutLineProc is called with an untyped variable containing a row's
  42.     worth of pixels. The current line is given in line and the number of
  43.     pixels in a line is given in width}
  44.     GifInPixelProc : GifPixelProcType;
  45. { GifInPixelProc should return a pixel value, -1 if at the end of the data.
  46.     Data should be returned width first (i.e. all pixels in row 0, then all
  47.     pixels in row 1, etc.}
  48.     GifPalette : array[0..767] of byte;
  49. { GifPalette is an array which contains the palette of the last loaded
  50.     GIF file}
  51.  
  52.  
  53.  
  54. function LoadGif( f : string ) : integer;
  55. { This function loads a GIF file f and returns an error code.
  56.     It uses the #GIFLineProc# procedure to send the decoded picture
  57.     to the application. The palette of the picture is stored in the
  58.     global variable #GifPalette#}
  59. function SaveGif( f : string; width, depth, bits : integer; var palette ) : integer;
  60. { This function saves a GIF file f with using screen size width*depth
  61.     and with a color resolution of bits. For a 256 colour image bits is 8.
  62.     Palette contains the palette of the picture that is being saved.
  63.     SaveGIF uses #GIFInPixelProc# to get the picture data from the application.
  64.     It returns an error code}
  65. function GifError( ErrorCode : integer ) : string;
  66. { This function converts an error code returned by SaveGIF into a string}
  67.  
  68. Implementation
  69.  
  70. type
  71.     GifHeader =
  72.         record
  73.             sig : array[1..6] of char;
  74.             screenwidth, screendepth : word;
  75.             flags, background, aspect : byte;
  76.         end;
  77.  
  78.     ImageBlock =
  79.         record
  80.             left, top, width, depth : word;
  81.             flags : byte;
  82.         end;
  83.  
  84.     FileInfo =
  85.         record
  86.             width, depth, bits,
  87.             flags, background : integer;
  88.             palette : array[1..768] of byte;
  89.         end;
  90.  
  91.     ControlBlock =
  92.         record
  93.             blocksize, flags : byte;
  94.             delay : word;
  95.             transparentcolour, terminator : byte;
  96.         end;
  97.  
  98.     PlainText =
  99.         record
  100.             blocksize : byte;
  101.             left, top, gridwidth, gridheight : word;
  102.             cellwidth, cellheight, forecolour, backcolour : byte;
  103.         end;
  104.  
  105.     Application =
  106.         record
  107.             blocksize : byte;
  108.             applstring : array[1..8] of char;
  109.             authentication : array[1..3] of char;
  110.         end;
  111.  
  112.  
  113. const
  114.     TableSize = 5003;
  115.     { These values will be masked with the codes output from the
  116.         decoder to remove spurious bits }
  117.     CodeMask : array[1..13] of word =
  118.         ( $0000,
  119.             $0001, $0003,
  120.             $0007, $000F,
  121.             $001F, $003F,
  122.             $007F, $00FF,
  123.             $01FF, $03FF,
  124.             $07FF, $0FFF );
  125.     LargestCode = 4095;
  126.  
  127. function UnpackImage( var F : File; bits : integer; Var fi : FileInfo ) : integer;
  128. var
  129.     bits2, codesize, codesize2, nextcode, thiscode,
  130.     oldtoken, currentcode, oldcode, bitsleft, blocksize,
  131.     line, pass, byt, p, q, u : integer;
  132.     b : array[0..255] of byte;
  133.     linebuffer, firstcodestack, lastcodestack : ^TByteArray;
  134.     codestack : ^TIntArray;
  135. const
  136.     wordmasktable : array[0..15] of word =
  137.         ( $0000, $0001, $0003, $0007, $000F, $001F,
  138.             $003F, $007F, $00FF, $01FF, $03FF, $07FF,
  139.             $0FFF, $1FFF, $3FFF, $7FFF );
  140.     inctable : array[0..4] of integer = ( 8, 8, 4, 2, 0 );
  141.     starttable : array[0..4] of integer = ( 0, 4, 2, 1, 0 );
  142. begin
  143.     pass := 0;
  144.     line := 0;
  145.     byt := 0;
  146.     p := 0;
  147.     q := 0;
  148.     blocksize := 0;
  149.     fillchar( b, 256, 0 );
  150.     bitsleft := 8;
  151.     if ( bits < 2 ) or ( bits > 8 ) then
  152.     begin
  153.         UnpackImage := BadSymbolSize;
  154.         exit;
  155.     end;
  156.     bits2 := 1 shl bits;
  157.     nextcode := bits2 + 2;
  158.     codesize := bits + 1;
  159.     codesize2 := 1 shl codesize;
  160.     oldcode := NoCode;
  161.     oldtoken := NoCode;
  162.     getmem( firstcodestack, 4096 );
  163.     getmem( lastcodestack, 4096 );
  164.     getmem( codestack, 8192 );
  165.     getmem( linebuffer, fi.width );
  166.     while true do
  167.     begin
  168.         if bitsleft = 8 then
  169.         begin
  170.             inc(p);
  171.             if p>=q then
  172.             begin
  173.                 blocksize := 0;
  174.                 blockread( F, blocksize, 1);
  175.                 if blocksize>0 then
  176.                 begin
  177.                     p:=0;
  178.                     blockread( F, b, blocksize, q );
  179.                     if q<>blocksize then
  180.                     begin
  181.                         freemem( firstcodestack, 4096 );
  182.                         freemem( lastcodestack, 4096 );
  183.                         freemem( codestack, 8192 );
  184.                         freemem( linebuffer, fi.width );
  185.                         UnpackImage := UnexpectedEOF;
  186.                         exit;
  187.                     end;
  188.                 end else
  189.                 begin
  190.                     freemem( firstcodestack, 4096 );
  191.                     freemem( lastcodestack, 4096 );
  192.                     freemem( codestack, 8192 );
  193.                     freemem( linebuffer, fi.width );
  194.                     UnpackImage := UnexpectedEOF;
  195.                     exit;
  196.                 end;
  197.             end;
  198.             bitsleft := 0;
  199.         end;
  200.         thiscode := b[p];
  201.         currentcode := codesize + bitsleft;
  202.         if currentcode <=8 then
  203.         begin
  204.             b[p] := b[p] shr codesize;
  205.             bitsleft := currentcode;
  206.         end else
  207.         begin
  208.             inc(p);
  209.             if p>=q then
  210.             begin
  211.                 blocksize := 0;
  212.                 blockread( F, blocksize, 1);
  213.                 if blocksize>0 then
  214.                 begin
  215.                     p:=0;
  216.                     blockread( F, b, blocksize, q );
  217.                     if q<>blocksize then
  218.                     begin
  219.                         freemem( firstcodestack, 4096 );
  220.                         freemem( lastcodestack, 4096 );
  221.                         freemem( codestack, 8192 );
  222.                         freemem( linebuffer, fi.width );
  223.                         UnpackImage := UnexpectedEOF;
  224.                         exit;
  225.                     end;
  226.                 end else
  227.                 begin
  228.                     freemem( firstcodestack, 4096 );
  229.                     freemem( lastcodestack, 4096 );
  230.                     freemem( codestack, 8192 );
  231.                     freemem( linebuffer, fi.width );
  232.                     UnpackImage := UnexpectedEOF;
  233.                     exit;
  234.                 end;
  235.             end;
  236.             thiscode := thiscode or ( b[p] shl (8-bitsleft) );
  237.             if currentcode <= 16 then
  238.             begin
  239.                 bitsleft := currentcode - 8;
  240.                 b[p] := b[p] shr bitsleft;
  241.             end else
  242.             begin
  243.                 inc(p);
  244.                 if p>=q then
  245.                 begin
  246.                     blocksize := 0;
  247.                     blockread( F, blocksize, 1);
  248.                     if blocksize>0 then
  249.                     begin
  250.                         p:=0;
  251.                         blockread( F, b, blocksize, q );
  252.                         if q<>blocksize then
  253.                         begin
  254.                             freemem( firstcodestack, 4096 );
  255.                             freemem( lastcodestack, 4096 );
  256.                             freemem( codestack, 8192 );
  257.                             freemem( linebuffer, fi.width );
  258.                             UnpackImage := UnexpectedEOF;
  259.                             exit;
  260.                         end;
  261.                     end else
  262.                     begin
  263.                         freemem( firstcodestack, 4096 );
  264.                         freemem( lastcodestack, 4096 );
  265.                         freemem( codestack, 8192 );
  266.                         freemem( linebuffer, fi.width );
  267.                         UnpackImage := UnexpectedEOF;
  268.                         exit;
  269.                     end;
  270.                 end;
  271.                 thiscode := thiscode or ( b[p] shl (16-bitsleft) );
  272.                 bitsleft := currentcode - 16;
  273.                 b[p] := b[p] shr bitsleft;
  274.             end;
  275.         end;
  276.         thiscode := thiscode and wordmasktable[codesize];
  277.         currentcode := thiscode;
  278.         if thiscode = bits2+1 then break;
  279.         if thiscode > nextcode then
  280.         begin
  281.             freemem( firstcodestack, 4096 );
  282.             freemem( lastcodestack, 4096 );
  283.             freemem( codestack, 8192 );
  284.             freemem( linebuffer, fi.width );
  285.             UnpackImage := BadCode;
  286.             exit;
  287.         end;
  288.         if thiscode = bits2 then
  289.         begin
  290.             nextcode := bits2+2;
  291.             codesize := bits + 1;
  292.             codesize2 := 1 shl codesize;
  293.             oldtoken := NoCode;
  294.             OldCode := NoCode;
  295.             continue;
  296.         end;
  297.         u := 0;
  298.         if thiscode = nextcode then
  299.         begin
  300.             if oldcode = NoCode then
  301.             begin
  302.                 freemem( firstcodestack, 4096 );
  303.                 freemem( lastcodestack, 4096 );
  304.                 freemem( codestack, 8192 );
  305.                 freemem( linebuffer, fi.width );
  306.                 UnpackImage := BadFirstCode;
  307.                 exit;
  308.             end;
  309.             firstcodestack^[u] := oldtoken;
  310.             inc( u );
  311.             thiscode := oldcode;
  312.         end;
  313.         while thiscode >= bits2 do
  314.         begin
  315.             firstcodestack^[u] := lastcodestack^[thiscode];
  316.             inc( u );
  317.             thiscode := codestack^[thiscode];
  318.         end;
  319.         oldtoken := thiscode;
  320.         while true do
  321.         begin
  322.             linebuffer^[byt] := thiscode;
  323.             inc( byt );
  324.             if byt >= fi.width then
  325.             begin
  326.                 GifOutLineProc( linebuffer^, line, fi.width );
  327.                 byt := 0;
  328.                 if fi.flags and $40 = $40 then
  329.                 begin
  330.                     line := line + inctable[pass];
  331.                     if line >= fi.depth then
  332.                     begin
  333.                         inc(pass);
  334.                         line := starttable[pass];
  335.                     end;
  336.                 end else inc(line);
  337.             end;
  338.             if u <= 0 then break;
  339.             dec( u );
  340.             thiscode := firstcodestack^[u];
  341.         end;
  342.         if (nextcode < 4096) and (oldcode <> NoCode) then
  343.         begin
  344.             codestack^[nextcode] := oldcode;
  345.             lastcodestack^[nextcode] := oldtoken;
  346.             inc( nextcode );
  347.             if (nextcode >= codesize2) and (codesize < 12) then
  348.             begin
  349.                 inc( codesize );
  350.                 codesize2 := 1 shl codesize;
  351.             end;
  352.         end;
  353.         oldcode := currentcode;
  354.     end;
  355.     freemem( firstcodestack, 4096 );
  356.     freemem( lastcodestack, 4096 );
  357.     freemem( codestack, 8192 );
  358.     freemem( linebuffer, fi.width );
  359.     UnpackImage := GoodRead;
  360. end; { UnpackImage }
  361.  
  362. procedure SkipExtension( Var F : File );
  363. var
  364.     pt : PlainText;
  365.     cb : ControlBlock;
  366.     ap : Application;
  367.     i : integer;
  368.     a, n, c : byte;
  369.     r : word;
  370. begin
  371.     blockread( F, c, 1 );
  372.     case c of
  373.         $01 :
  374.             begin
  375.                 blockread( F, pt, sizeof( PlainText ) );
  376.                 blockread( F, n, 1 );
  377.                 while n > 0 do
  378.                 begin
  379.                     for i := 0 to n-1 do
  380.                         blockread( F, a, 1 );
  381.                     blockread( F, n, 1 );
  382.                 end;
  383.             end;
  384.         $F9 :
  385.             blockread( F, cb, sizeof( ControlBlock ) );
  386.         $FE :
  387.             begin
  388.                 blockread( F, n, 1 );
  389.                 while n > 0 do
  390.                 begin
  391.                     for i:= 0 to n-1 do
  392.                         blockread( F, a, 1 );
  393.                     blockread( F, n, 1 );
  394.                 end;
  395.             end;
  396.         $FF :
  397.             begin
  398.                 blockread( F, ap, sizeof( Application ) );
  399.                 blockread( F, n, 1 );
  400.                 while n > 0 do
  401.                 begin
  402.                     for i := 0 to n-1 do
  403.                         blockread( F, a, 1 );
  404.                     blockread( F, n, 1 );
  405.                 end;
  406.             end;
  407.         else
  408.             begin
  409.                 blockread( F, n, 1 );
  410.                 for i := 0 to n-1 do
  411.                         blockread( F, a, 1 );
  412.             end;
  413.     end;
  414. end; { SkipExtension }
  415.  
  416. function UnpackGIF( Var F : File ) : integer;
  417. var
  418.     gh : GifHeader;
  419.     iblk : ImageBlock;
  420.     t : longint;
  421.     b, c : integer;
  422.     r : word;
  423.     ch : char;
  424.     fi : FileInfo;
  425. begin
  426.     blockread( F, gh, SizeOf(GifHeader), r );
  427.     if ( gh.sig[1]+gh.sig[2]+gh.sig[3]<>'GIF' ) or ( r<>SizeOf(GifHeader) ) then
  428.     begin
  429.         UnpackGIF := BadFile;
  430.         exit;
  431.     end;
  432.     fi.width := gh.screenwidth;
  433.     fi.depth := gh.screendepth;
  434.     fi.bits := gh.flags and $07 + 1;
  435.     fi.background := gh.background;
  436.     if ( gh.flags and $80 )=$80 then
  437.     begin
  438.         c:=3*( 1 shl fi.bits );
  439.         blockread( F, fi.palette, c, r );
  440.         if r<>c then
  441.         begin
  442.             UnpackGIF := BadRead;
  443.             exit;
  444.         end;
  445.         for b := 0 to 255 do
  446.         begin
  447.             GIFPalette[b*3] := fi.palette[b*3+1] shr 2;
  448.             GIFPalette[b*3+1] := fi.palette[b*3+2] shr 2;
  449.             GIFPalette[b*3+2] := fi.palette[b*3+3] shr 2;
  450.         end;
  451.  
  452.     end;
  453.     blockread( F, ch, 1 );
  454.     while ( ch = ',' ) or ( ch = '!' ) or ( ch = #0 ) do
  455.     begin
  456.         case ch of
  457.             ',' : begin
  458.                             blockread( F, iblk, SizeOf(ImageBlock), r );
  459.                             if r<>SizeOf(ImageBlock) then
  460.                             begin
  461.                                 UnpackGIF := BadRead;
  462.                                 Exit;
  463.                             end;
  464.                             fi.width := iblk.width;
  465.                             fi.depth := iblk.depth;
  466.                             if ( iblk.flags and $80 )=$80 then
  467.                             begin
  468.                                 b := 3*(1 shl (iblk.flags and $07 + 1));
  469.                                 blockread( F, fi.palette, b, r );
  470.                                 if r<>b then
  471.                                 begin
  472.                                     UnpackGIF := BadRead;
  473.                                     Exit;
  474.                                 end;
  475.                                 for b := 0 to 255 do
  476.                                 begin
  477.                                     GIFPalette[b*3] := fi.palette[b*3+1] shr 2;
  478.                                     GIFPalette[b*3+1] := fi.palette[b*3+2] shr 2;
  479.                                     GIFPalette[b*3+1] := fi.palette[b*3+3] shr 2;
  480.                                 end;
  481.                             end;
  482.                             if EOF( F ) then
  483.                             begin
  484.                                 UnpackGIF := BadFile;
  485.                                 Exit;
  486.                             end;
  487.                             c:=0;
  488.                             blockread( F, c, 1 );
  489.                             fi.flags:=iblk.flags;
  490.                             t := UnpackImage( F, c, fi );
  491.                             UnpackGif:=t;
  492.                             exit;
  493.                         end;
  494.             '!' : SkipExtension( F );
  495.         end;
  496.     end;
  497. end; { UnpackGIF }
  498.  
  499. function LoadGif;
  500. var
  501.     D: DirStr;
  502.     N: NameStr;
  503.     E: ExtStr;
  504.     FileHandle : File;
  505. begin
  506.     FSplit( F, D, N, E );
  507.     if E='' then E:='.GIF';
  508.     F := D+N+E;
  509.     {$I-}
  510.         assign( FileHandle, F );
  511.         reset( FileHandle, 1 );
  512.     {$I+}
  513.     if ioresult = 0 then
  514.         LoadGif := UnpackGif( FileHandle )
  515.     else
  516.         LoadGif := NoFile;
  517.     {$I-}
  518.         close( FileHandle );
  519.     {$I+}
  520. end; { LoadGif }
  521.  
  522. function WriteScreenDesc( var fp : file; width, depth, bits, background : integer; var palette ) : integer;
  523. var
  524.     gh : GIFHeader;
  525.     i : integer;
  526.     gifsig : string;
  527.     pal : TByteArray absolute palette;
  528.     a : byte;
  529. begin
  530.     FillChar( gh, sizeof(GIFHeader),0 );
  531.     gifsig := 'GIF87a';
  532.     move( gifsig[1], gh.sig[1], 6 );
  533.     gh.screenwidth := width;
  534.     gh.screendepth := depth;
  535.     gh.background := background;
  536.     gh.aspect := 0;
  537.     gh.flags := $80 or ((bits-1) shl 4) or ((bits-1) and $07);
  538.     blockwrite( fp, gh, sizeof(GIFHeader) );
  539.     for i := 0 to (1 shl bits)*3-1 do
  540.     begin
  541.         a := pal[i] shl 2;
  542.         blockwrite( fp, a, 1 );
  543.     end;
  544.     WriteScreenDesc := 0;
  545. end;
  546.  
  547. function WriteImageDesc( var fp : file; left, top, width, depth, bits : integer ) : integer;
  548. var
  549.     ib : ImageBlock;
  550.     ch : char;
  551. begin
  552.     fillchar( ib, sizeof(ImageBlock), 0 );
  553.     ch := ',';
  554.     blockwrite( fp, ch, 1 );
  555.     ib.left := left;
  556.     ib.top := top;
  557.     ib.width := width;
  558.     ib.depth := depth;
  559.     ib.flags := bits-1;
  560.     blockwrite( fp, ib, sizeof(ImageBlock) );
  561.     WriteImageDesc := 0;
  562. end;
  563.  
  564.  
  565. function CompressImage( var fp : file; mincodesize : word ) : integer;
  566. var
  567.     prefixcode, suffixchar, hx, d : integer;
  568.     codebuffer, newcode : ^TByteArray;
  569.     oldcode, currentcode : ^TIntArray;
  570.     codesize, clearcode, eofcode, bitoffset,
  571.     byteoffset, bitsleft, maxcode, freecode : integer;
  572.  
  573.  
  574.     procedure InitTable( mincodesize : integer );
  575.     var
  576.         i : integer;
  577.     begin
  578.         codesize := mincodesize + 1;
  579.         clearcode := 1 shl mincodesize;
  580.         eofcode := clearcode+1;
  581.         freecode := clearcode+2;
  582.         maxcode := 1 shl codesize;
  583.         for i := 0 to tablesize-1 do
  584.             currentcode^[i] := 0;
  585.     end;
  586.  
  587.     procedure Deallocate;
  588.     begin
  589.         freemem( newcode, tablesize+1 );
  590.         freemem( currentcode, (tablesize+1)*2 );
  591.         freemem( oldcode, (tablesize+1)*2 );
  592.         freemem( codebuffer, 260 );
  593.     end;
  594.  
  595.     procedure FlushFile( var fp : file; n : integer );
  596.     var
  597.         a : byte;
  598.     begin
  599.         a := n;
  600.         blockwrite( fp, a, 1 );
  601.         blockwrite( fp, codebuffer^[0], n );
  602.     end;
  603.  
  604.     procedure WriteCode( var fp : file; code : integer );
  605.     var
  606.         temp : longint;
  607.     begin
  608.         byteoffset := bitoffset shr 3;
  609.         bitsleft := bitoffset and 7;
  610.         if byteoffset >= 254 then
  611.         begin
  612.             FlushFile( fp, byteoffset );
  613.             codebuffer^[0] := codebuffer^[byteoffset];
  614.             bitoffset := bitsleft;
  615.             byteoffset := 0;
  616.         end;
  617.         if bitsleft > 0 then
  618.         begin
  619.             temp := ( longint(code) shl bitsleft ) or codebuffer^[byteoffset];
  620.             codebuffer^[byteoffset] := temp;
  621.             codebuffer^[byteoffset+1] := temp shr 8;
  622.             codebuffer^[byteoffset+2] := temp shr 16;
  623.         end else
  624.         begin
  625.             codebuffer^[byteoffset] := code;
  626.             codebuffer^[byteoffset+1] := code shr 8;
  627.         end;
  628.         bitoffset := bitoffset + codesize;
  629.     end;
  630.  
  631.  
  632. begin
  633.     if (mincodesize<2) or (mincodesize>9) then
  634.         if mincodesize = 1 then
  635.             mincodesize := 2
  636.         else
  637.         begin
  638.             CompressImage := 1;
  639.             exit;
  640.         end;
  641.     getmem( codebuffer, 260 );
  642.     getmem( oldcode, (tablesize+1)*2 );
  643.     getmem( currentcode, (tablesize+1)*2 );
  644.     getmem( newcode, tablesize+1 );
  645.     bitoffset := 0;
  646.     InitTable( mincodesize );
  647.     blockwrite( fp, mincodesize, 1 );
  648.     suffixchar := GIFInPixelProc;
  649.     if suffixchar < 0 then
  650.     begin
  651.         CompressImage := 1;
  652.         Deallocate;
  653.         exit;
  654.     end;
  655.     prefixcode := suffixchar;
  656.     suffixchar := GIFInPixelProc;
  657.     while suffixchar>=0 do
  658.     begin
  659.         hx := (prefixcode xor (suffixchar shl 5)) mod tablesize;
  660.         d := 1;
  661.         while true do
  662.         begin
  663.             if currentcode^[hx] = 0 then
  664.             begin
  665.                 writecode( fp, prefixcode );
  666.                 d := freecode;
  667.                 if freecode <= largestcode then
  668.                 begin
  669.                     oldcode^[hx] := prefixcode;
  670.                     newcode^[hx] := suffixchar;
  671.                     currentcode^[hx] := freecode;
  672.                     inc(freecode);
  673.                 end;
  674.                 if d=maxcode then
  675.                 begin
  676.                     if codesize<12 then
  677.                     begin
  678.                         inc(codesize);
  679.                         maxcode := maxcode shl 1;
  680.                     end else
  681.                     begin
  682.                         writecode( fp, clearcode );
  683.                         InitTable( mincodesize );
  684.                     end;
  685.                 end;
  686.                 prefixcode := suffixchar;
  687.                 break;
  688.             end;
  689.             if (oldcode^[hx] = prefixcode) and (newcode^[hx] = suffixchar ) then
  690.             begin
  691.                 prefixcode := currentcode^[hx];
  692.                 break;
  693.             end;
  694.             hx := hx + d;
  695.             d := d + 2;
  696.             if hx >= tablesize then hx := hx - tablesize;
  697.         end;
  698.         suffixchar := GIFInPixelProc;
  699.     end;
  700.     writecode( fp, prefixcode );
  701.     writecode( fp, eofcode );
  702.     if bitoffset >0 then FlushFile( fp, (bitoffset+7) div 8 );
  703.     FlushFile( fp, 0 );
  704.     CompressImage := 0;
  705.     Deallocate;
  706. end;
  707.  
  708.  
  709. function WriteGif( var fp : file; width, depth, bits : integer; var palette ) : integer;
  710. var
  711.     ch : char;
  712. begin
  713.     if WriteScreenDesc( fp, width, depth, bits, 0, palette )>0 then
  714.         WriteGIF := 1
  715.     else
  716.     if WriteImageDesc( fp, 0, 0, width, depth, bits )>0 then
  717.         WriteGIF := 2
  718.     else
  719.     if CompressImage( fp, bits )>0 then
  720.         WriteGIF := 3
  721.     else
  722.     begin
  723.         WriteGIF := 0;
  724.         ch := ';';
  725.         blockwrite( fp, ch, 1 );
  726.     end;
  727. end;
  728.  
  729. function SaveGif( f : string; width, depth, bits : integer; var palette ) : integer;
  730. var
  731.     D: DirStr;
  732.     N: NameStr;
  733.     E: ExtStr;
  734.     FileHandle : File;
  735. begin
  736.     FSplit( F, D, N, E );
  737.     if E='' then E:='.GIF';
  738.     F := D+N+E;
  739.     {$I-}
  740.         assign( FileHandle, F );
  741.         rewrite( FileHandle, 1 );
  742.     {$I+}
  743.     if ioresult = 0 then
  744.         SaveGif := WriteGif( FileHandle, width, depth, bits, palette  )
  745.     else
  746.         SaveGif := NoFile;
  747.     {$I-}
  748.         close( FileHandle );
  749.     {$I+}
  750. end;
  751.  
  752. function GifError;
  753. begin
  754.     case ErrorCode of
  755.         GoodRead : GifError := 'Ok';
  756.         BadFile  : GifError := 'Bad File';
  757.         BadRead  : GifError := 'Bad Read';
  758.         UnexpectedEOF : GifError := 'Unexpected End';
  759.         BadCode       : GifError := 'Bad LZW Code';
  760.         BadFirstCode  : GifError := 'Bad First Code';
  761.         BadSymbolSize : GifError := 'Bad Symbol Size';
  762.         NoFile        : GifError := 'File Not Found';
  763.         else GifError := 'Unknown';
  764.     end;
  765. end; { GifError }
  766.  
  767.  
  768. end.
  769.